﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RPGProject.GameWorld.GameObjects
{
    /// <summary>
    /// A basic character class, that associates a world with the character and has a typeId of "character"
    /// </summary>
    class Character : WorldSpecificGameObject
    {
        /// <summary>
        /// Generates a character from the parameters.
        /// </summary>
        /// <param name="x">Location of the character along the x axis.</param>
        /// <param name="y">Location of the character along the x axis.</param>
        /// <param name="icon">The icon to give the character.</param>
        /// <param name="color">The color to give the character.</param>
        /// <param name="name">The name of the character.</param>
        /// <param name="world">The world the character resides in.</param>
        protected Character(int x, int y, int maxhp, char icon, ConsoleColor color, String name, World world, String typeId = "character")
            : base(x, y, icon, color, name, world, typeId)
        {
            this["maxhp"] = this["hp"] = maxhp;
        }
        /// <summary>
        /// Listens to a GameObjectEvent, from GameObject.
        /// </summary>
        /// <param name="e">The event to listen to.</param>
        /// <returns>An event if needed.</returns>
        public override GameObjectEvent Listen(GameObjectEvent e)
        {
            // events that have this as a target.
            if (e.Has("target") && e["target"] == this)
            {
                GameObjectEvent ret;
                switch(e.Name)
                {
                    case "damage":
                        this["hp"] = (int)this["hp"] - (int)e["damage"];
                        this.InvariantHealth((GameObject)e["source"]);
                        break;
                    case "kill":
                        // sees a kill event, and tells the world
                        // that its dead
                        ret = new GameObjectEvent("death");
                        ret["source"] = this;
                        this.world.Listen(ret);
                        break;
                    case "moveAttempt":
                        // if something tries to move into it, it instead collides
                        ret = new GameObjectEvent("collision");
                        ret.Grab(e);
                        ret["target"] = this;
                        ret["source"] = e["source"];
                        this.world.Listen(ret);
                        break;
                }
                
            }
            // events that have this as a source
            if (e.Has("source") && ((GameObject)e["source"]) == this)
            {
            }
            return null;
        }
        /// <summary>
        /// Gets a damage event with this as the source.
        /// </summary>
        /// <returns></returns>
        public GameObjectEvent GetDamageEvent()
        {
            GameObjectEvent ret = new GameObjectEvent("damage");
            ret["source"] = this;
            return ret;
        }
        /// <summary>
        /// Make sure hp is above 0, if its not tell the world to do garbage collection.
        /// </summary>
        /// <param name="source">The killing object.</param>
        public virtual void InvariantHealth(GameObject source)
        {
            if ((int)this["hp"] <= 0)
            {
                GameObjectEvent ret = new GameObjectEvent("kill");
                ret["target"] = this;
                ret["source"] = source;
                this.world.Listen(ret);
            }
        }
        /// <summary>
        /// Gets an moveAttempt event with this as the source.
        /// </summary>
        /// <returns>An moveAttempt event.</returns>
        public GameObjectEvent GetMoveEvent()
        {
            GameObjectEvent ret = new GameObjectEvent("moveAttempt");
            ret["source"] = this;
            return ret;
        }
        /// <summary>
        /// An overriden version of Equals to check for Character equality.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj is Character)
            {
                Character c = (Character)obj;
                if (base.Equals(c))
                {
                    return true;
                }
            }
            return false;
        }
    }
}
